﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  DispatcherTest.cs
//    
// Abstract:
//
//  Unit tests for the Dispatcher
//  
//--

using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.OfficeCommunicationsServer.Applications.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.EnhancedReminders.Dispatcher.UnitTests
{    
    /// <summary>
    ///This is a test class for DispatcherTest and is intended
    ///to contain all DispatcherTest Unit Tests
    ///</summary>
    [TestClass()]
    public class DispatcherTest : IDisposable
    {
        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //

        /// <summary>
        /// Initializes the AutoResetEvent used for waiting for async calls
        /// to complete.
        /// </summary>
        [TestInitialize()]
        public void MyTestInitialize()
        {
            _waitEvent = new AutoResetEvent(false);
        }

        /// <summary>
        /// Closes the AutoResetEvent used in some tests.
        /// </summary>
        [TestCleanup()]
        public void MyTestCleanup()
        {
            _waitEvent.Close();
        }
        
        #endregion

        private AutoResetEvent _waitEvent;
        private NotificationResult _result;
        private DispatcherTestClassFactory _factory;

        private NotificationResult DeliverNotification(NotificationDispatcher target, NotificationItem notificiation)
        {
            target.DeliverNotificationCompleted += DeliverNotificationCompleted;
            target.DeliverNotificationAsync(notificiation);
            _waitEvent.WaitOne(1000, false);

            return _result;
        }

        private void DeliverNotificationCompleted(object sender, DeliveryCompletedEventArgs e)
        {
            (sender as NotificationDispatcher).DeliverNotificationCompleted -= DeliverNotificationCompleted;
            _result = e.Result;
            _waitEvent.Set();
        }

        /// <summary>
        /// Test a delivery attempt of an instant message notification to an endpoint
        /// that is currently offline and that should only receive notifications when away.
        /// </summary>
        [TestMethod()]
        public void TestFailedIMNotificationPresenceRulesDoNotMatch()
        {
            _factory = new DispatcherTestClassFactory();
            NotificationDispatcher target = new NotificationDispatcher(_factory);
            ReminderItem reminderItem = new ReminderItem(new List<NotificationChannel>());
            reminderItem.NotificationChannelList.Channels.Add(new NotificationChannel(NotificationChannelType.Communicator));
            reminderItem.Presence = PresenceStates.Away;

            CalendarNotificationItem notification = new CalendarNotificationItem(Context.Global,
                new NotificationId("1", "john@contoso.com"), "john@contoso.com", DateTime.UtcNow, reminderItem, "John Contoso", false /* hasBody */,
                "Office", "This is a test appointment", DateTime.UtcNow);

            _factory.AddMockUser("john@contoso.com", "sip:john@contoso.com", PresenceStates.Offline);

            NotificationResult expectedResult = new NotificationResult(notification.Context, notification.Id, NotificationResultStatus.Error, NotificationChannelType.None);
            NotificationResult actualResult = DeliverNotification(target, notification);

            Assert.AreEqual(expectedResult.Id, actualResult.Id, "Actual result ID does not match expected successful result ID");
            Assert.AreEqual(expectedResult.Status, actualResult.Status, "Actual result status does not match expected successful result status");
            Assert.AreEqual(expectedResult.HowContacted, actualResult.HowContacted, "Actual result channel does not match expected successful result channel");
        }

        /// <summary>
        /// Test a delivery attempt of a notification with no reminder items.
        /// </summary>
        [TestMethod()]
        public void TestFailedNotificationNoChannels()
        {
            _factory = new DispatcherTestClassFactory();
            NotificationDispatcher target = new NotificationDispatcher(_factory);
            ReminderItem reminderItem = new ReminderItem(new List<NotificationChannel>());

            CalendarNotificationItem notification = new CalendarNotificationItem(Context.Global,
                new NotificationId("id", "john@contoso.com"), "john@contoso.com", DateTime.UtcNow, reminderItem, "John Contoso", false /* hasBody */,
                "Office", "This is a test appointment", DateTime.UtcNow);

            _factory.AddMockUser("john@contoso.com", "sip:john@contoso.com", PresenceStates.Offline);

            NotificationResult expectedResult = new NotificationResult(notification.Context, notification.Id, NotificationResultStatus.Error, NotificationChannelType.None);
            NotificationResult actualResult = DeliverNotification(target, notification);

            Assert.AreEqual(expectedResult.Id, actualResult.Id, "Actual result ID does not match expected successful result ID");
            Assert.AreEqual(expectedResult.Status, actualResult.Status, "Actual result status does not match expected successful result status");
            Assert.AreEqual(expectedResult.HowContacted, actualResult.HowContacted, "Actual result channel does not match expected successful result channel");
        }

        #region IDisposable Members

        /// <summary>
        /// Release all resources used by the test class.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_waitEvent != null)
                {
                    _waitEvent.Close();
                    _waitEvent = null;
                }

                if (_factory != null)
                {
                    _factory.Dispose();
                    _factory = null;
                }
            }
        }

        #endregion
    }
}
